package ro.one.gaeql.model;

public class MathOperatorEvaluator implements OperatorEvaluator {	
	
	@Override
	public Object eval(Object leftValue, AssignExpressionOperator op, Object rightValue) {
		if (leftValue instanceof Long) {
			if (rightValue instanceof Long) {
				return longWithLong((Long)leftValue, (Long)rightValue, op);
			}
			if (rightValue instanceof Integer) {
				return longWithInt((Long)leftValue, (Integer)rightValue, op);
			}
			else if (rightValue instanceof Float) {
				return longWithFloat((Long)leftValue, (Float)rightValue, op);
			}
			else {
				throw new RuntimeException("Unsupported operand types.");
			}
		}
		
		if (leftValue instanceof Integer) {
			if (rightValue instanceof Long) {
				return intWithLong((Integer)leftValue, (Long)rightValue, op);
			}
			if (rightValue instanceof Integer) {
				return intWithInt((Integer)leftValue, (Integer)rightValue, op);
			}
			else if (rightValue instanceof Float) {
				return intWithFloat((Integer)leftValue, (Float)rightValue, op);
			}
			else {
				throw new RuntimeException("Unsupported operand types.");
			}
		}
		
		if (leftValue instanceof Float) {
			if (rightValue instanceof Long) {
				return floatWithLong((Float)leftValue, (Long)rightValue, op);
			}
			if (rightValue instanceof Integer) {
				return floatWithInt((Float)leftValue, (Integer)rightValue, op);
			}
			else if (rightValue instanceof Float) {
				return floatWithFloat((Float)leftValue, (Float)rightValue, op);
			}
			else {
				throw new RuntimeException("Unsupported operand types.");
			}
		}		
		
		throw new RuntimeException("Unsupported operand types.");
	}
	
	private Object intWithInt(Integer int1, Integer int2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return int1 + int2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return int1 - int2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object intWithFloat(Integer int1, Float float2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return int1 + float2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return int1 - float2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object intWithLong(Integer int1, Long long2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return int1 + long2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return int1 - long2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object floatWithInt(Float float1, Integer int2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return float1 + int2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return float1 - int2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object floatWithFloat(Float float1, Float float2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return float1 + float2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return float1 - float2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object floatWithLong(Float float1, Long long2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return float1 + long2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return float1 - long2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object longWithInt(Long long1, Integer int2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return long1 + int2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return long1 - int2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object longWithFloat(Long long1, Float float2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return long1 + float2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return long1 - float2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}
	
	private Object longWithLong(Long long1, Long long2, AssignExpressionOperator op) {
		if(op == AssignExpressionOperator.Plus) {
			return long1 + long2;
		}
		else if (op == AssignExpressionOperator.Minus) {
			return long1 - long2;
		}
		else {
			throw new RuntimeException("Unsupported operator.");
		}
	}

	@Override
	public boolean canHandle(AssignExpressionOperator op) {
		return op == AssignExpressionOperator.Divide ||
				op == AssignExpressionOperator.Minus ||
				op == AssignExpressionOperator.Multiply ||
				op == AssignExpressionOperator.Plus;
	}

}
